package com.cssw.fyzb.core.dao.acct;

import com.cssw.fyzb.core.model.dodb.Acct;
import com.cssw.fyzb.core.model.dodb.AcctLog;
import com.cssw.fyzb.core.model.dodb.AcctType;
import com.cssw.fyzb.core.util.BigDecimalUtl;
import com.cssw.fyzb.core.util.BizUtil;
import com.ydn.dbframe.plugin.activerecord.Page;
import com.ydn.dbframe.plugin.activerecord.parse.SqlParse;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.cssw.fyzb.core.util.Bizs.ERROR_ACCT_DATA;
import static com.cssw.fyzb.core.util.Bizs.ERROR_ACCT_DATA_CHANGE;

/**
 * @Author zhouxu
 * @create 2020-12-17 22:05
 */
@Repository
public class AcctDaoImpl implements AcctDao {

    @Override
    public void updateAcct(Acct acct) {
        // 账本值大于等于0才能更新
        if (!(BigDecimalUtl.isGreaterThanEqualsZero(acct.getBalanceFee())
                && BigDecimalUtl.isGreaterThanEqualsZero(acct.getTotalFee())
                && BigDecimalUtl.isGreaterThanEqualsZero(acct.getForzenFee()))) {
            BizUtil.exception(ERROR_ACCT_DATA);
        }
        acct.update();
    }

    @Override
    public Long createAcct(Long userId, String acctType) {
        Acct acct = new Acct();
        acct.setUserId(userId);
        acct.setAcctType(acctType);
        acct.setBalanceFee(BigDecimal.ZERO);
        acct.setForzenFee(BigDecimal.ZERO);
        acct.setTotalFee(BigDecimal.ZERO);
        acct.setIsCashOut(Acct.IS_CASH_OUT_NO);
        acct.setIsTransferAcct(Acct.IS_TRANSFER_NO);
        acct.save();

        return acct.getAcctId();
    }

    @Override
    public void createAcct(Long userId) {
        createAcct(userId, AcctType.ACCT_TYPE_F);
        createAcct(userId, AcctType.ACCT_TYPE_Y);
        createAcct(userId, AcctType.ACCT_TYPE_G);
    }

    @Override
    public Acct queryFAcct(Long userId) {
        return queryAcctByUIdAndType(userId, AcctType.ACCT_TYPE_F);
    }

    @Override
    public Acct queryYAcct(Long userId) {
        return queryAcctByUIdAndType(userId, AcctType.ACCT_TYPE_Y);
    }

    @Override
    public Acct queryGAcct(Long userId) {
        return queryAcctByUIdAndType(userId, AcctType.ACCT_TYPE_G);
    }

    @Override
    public Acct queryAcctByUIdAndType(Long userId, String acctType) {
        String sql = "select * from t_acct where user_id = ? and acct_type = ?";
        return Acct.dao.findFirst(sql, userId, acctType);
    }

    @Override
    public Acct queryAcctById(Long acctId) {
        return Acct.dao.findById(acctId);
    }

    @Override
    public List<Acct> listAcctByUserId(Long userId) {
        String sql = "select * from t_acct where user_id = ?";
        return Acct.dao.find(sql, userId);
    }

    @Override
    public Page<AcctLog> listAcctLog(Map param, int page, int limit) {
        SqlParse sqlParse = new SqlParse(param);
        sqlParse.addSQL(" select t1.*, ");
        sqlParse.addSQL(" (select trade_type_name from d_acct_trade_type t2 where t2.trade_type = t1.trade_type) as trade_name, ");
        sqlParse.addSQL(" (select busi_type_name from d_busi_type t2 where t2.busi_type = t1.busi_type) as busi_name ");
        sqlParse.addSQL("  from t_acct_log t1 ");
        sqlParse.addSQL(" where 1 = 1 ");
        sqlParse.addSQL(" and acct_id = :acctId ");
        sqlParse.addSQL(" and acct_type = :acctType ");
        sqlParse.addSQL(" and fee_in_de = :feeInDe ");
        sqlParse.addSQL(" order by log_id desc ");
        return AcctLog.dao.paginate(page, limit, sqlParse);
    }

    @Override
    public void addBalance(Long userId, String acctType, BigDecimal value,
                           String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctByUIdAndType(userId, acctType);
        if(acct==null){
            this.createAcct(userId, acctType);
            acct = queryAcctByUIdAndType(userId, acctType);
        }
        addBalance(acct, value, tradeId, tradeType, busiType);
    }

    @Override
    public void addFBalance(Long userId, BigDecimal value, String tradeId, String tradeType, String busiType) {
        addBalance(userId, AcctType.ACCT_TYPE_F, value, tradeId, tradeType, busiType);
    }

    @Override
    public void addYBalance(Long userId, BigDecimal value, String tradeId, String tradeType, String busiType) {
        addBalance(userId, AcctType.ACCT_TYPE_Y, value, tradeId, tradeType, busiType);
    }

    @Override
    public void addGBalance(Long userId, BigDecimal value, String tradeId, String tradeType, String busiType) {
        addBalance(userId, AcctType.ACCT_TYPE_G, value, tradeId, tradeType, busiType);
    }

    @Override
    public void addBalance(Long acctId, BigDecimal value,
                           String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctById(acctId);
        addBalance(acct, value, tradeId, tradeType, busiType);
    }

    @Override
    public void addBalance(Acct acct, BigDecimal value,
                           String tradeId, String tradeType, String busiType) {
        if (!BigDecimalUtl.isGreaterThanZero(value)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        acct.setBalanceFee(acct.getBalanceFee().add(value));

        //记录总费用
        acct.setTotalFee(acct.getTotalFee().add(value));
        updateAcct(acct);

        addAcctLog(acct, Acct.FEE_IN_DE_ADD, value, tradeId, tradeType, busiType);
    }

    @Override
    public void addBalance(Long userId, String acctType, BigDecimal value) {
        if (!BigDecimalUtl.isGreaterThanZero(value)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        Acct acct = queryAcctByUIdAndType(userId, acctType);
        acct.setBalanceFee(acct.getBalanceFee().add(value));
        updateAcct(acct);
    }


    @Override
    public void minusBalance(Long userId, String acctType, BigDecimal value) {
        if (!BigDecimalUtl.isGreaterThanZero(value)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        Acct acct = queryAcctByUIdAndType(userId, acctType);
        acct.setBalanceFee(acct.getBalanceFee().subtract(value));
        updateAcct(acct);
    }

    @Override
    public void minusBalance(Long acctId, BigDecimal value,
                             String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctById(acctId);
        minusBalance(acct, value, tradeId, tradeType, busiType);
    }

    @Override
    public void minusBalance(Long userId, String acctType, BigDecimal value,
                             String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctByUIdAndType(userId, acctType);
        minusBalance(acct, value, tradeId, tradeType, busiType);
    }


    @Override
    public void minusBalance(Acct acct, BigDecimal value,
                             String tradeId, String tradeType, String busiType) {
        if (!BigDecimalUtl.isGreaterThanZero(value)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        acct.setBalanceFee(acct.getBalanceFee().subtract(value));
        updateAcct(acct);

        addAcctLog(acct, Acct.FEE_IN_DE_MINUS, value, tradeId, tradeType, busiType);
    }


    @Override
    public void minusFrozenBalance(Long acctId, BigDecimal value,
                                   String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctById(acctId);
        minusFrozenBalance(acct, value, tradeId, tradeType, busiType);
    }

    @Override
    public void minusFrozenBalance(Long userId, String acctType, BigDecimal value,
                                   String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctByUIdAndType(userId, acctType);
        minusFrozenBalance(acct, value, tradeId, tradeType, busiType);
    }

    @Override
    public void minusFrozenBalance(Acct acct, BigDecimal value,
                                   String tradeId, String tradeType, String busiType) {
        if (!BigDecimalUtl.isGreaterThanZero(value)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        acct.setForzenFee(acct.getForzenFee().subtract(value));
        updateAcct(acct);

        addAcctLog(acct, Acct.FEE_IN_DE_MINUS, value, tradeId, tradeType, busiType);
    }

    @Override
    public void minusFBalance(Long userId, BigDecimal value, String tradeId, String tradeType, String busiType) {
        minusBalance(userId, AcctType.ACCT_TYPE_F, value, tradeId, tradeType, busiType);
    }

    @Override
    public void minusYBalance(Long userId, BigDecimal value, String tradeId, String tradeType, String busiType) {
        minusBalance(userId, AcctType.ACCT_TYPE_Y, value, tradeId, tradeType, busiType);
    }

    @Override
    public void minusGBalance(Long userId, BigDecimal value, String tradeId, String tradeType, String busiType) {
        minusBalance(userId, AcctType.ACCT_TYPE_G, value, tradeId, tradeType, busiType);
    }

    @Override
    public void frozenBalance(Long acctId, BigDecimal value,
                              String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctById(acctId);
        frozenBalance(acct, value, tradeId, tradeType, busiType);
    }


    @Override
    public void frozenBalance(Long userId, String acctType, BigDecimal value,
                              String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctByUIdAndType(userId, acctType);
        frozenBalance(acct, value, tradeId, tradeType, busiType);
    }


    @Override
    public void frozenBalance(Acct acct, BigDecimal value,
                              String tradeId, String tradeType, String busiType) {
        if (!BigDecimalUtl.isGreaterThanZero(value)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        // 1-减少余额
        BigDecimal newBalanceFee = acct.getBalanceFee().subtract(value);
        acct.setBalanceFee(newBalanceFee);

        // 2-增加冻结余额
        BigDecimal newFrozenFee = acct.getForzenFee().add(value);
        acct.setForzenFee(newFrozenFee);

        updateAcct(acct);

        addAcctLog(acct, Acct.FEE_IN_DE_MINUS, value, tradeId, tradeType, busiType);
    }

    @Override
    public void unfrozenBalance(Long userId, String acctType, BigDecimal value, String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctByUIdAndType(userId, acctType);

        unfrozenBalance(acct, value, tradeId, tradeType, busiType);
    }

    @Override
    public void unfrozenBalance(Long acctId, BigDecimal value, String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctById(acctId);

        unfrozenBalance(acct, value, tradeId, tradeType, busiType);
    }

    @Override
    public void unfrozenBalance(Acct acct, BigDecimal value, String tradeId, String tradeType, String busiType) {
        if (!BigDecimalUtl.isGreaterThanZero(value)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        // 1-增加余额
        BigDecimal newBalanceFee = acct.getBalanceFee().add(value);
        acct.setBalanceFee(newBalanceFee);

        // 2-减少冻结余额
        BigDecimal newFrozenFee = acct.getForzenFee().subtract(value);
        acct.setForzenFee(newFrozenFee);
        updateAcct(acct);

        addAcctLog(acct, Acct.FEE_IN_DE_ADD, value, tradeId, tradeType, busiType);
    }

    @Override
    public void addAcctLog(Long userId, String acctType, String feeInDe,
                           BigDecimal fee, String tradeId, String tradeType, String busiType) {
        Acct acct = queryAcctByUIdAndType(userId, acctType);

        addAcctLog(acct, feeInDe, fee, tradeId, tradeType, busiType);
    }

    @Override
    public void addAcctLog(Long acctId, String feeInDe, BigDecimal fee,
                           String tradeId, String tradeType, String busiType) {
        if (!BigDecimalUtl.isGreaterThanZero(fee)) {
            BizUtil.exception(ERROR_ACCT_DATA_CHANGE);
        }
        Acct acct = queryAcctById(acctId);
        addAcctLog(acct, feeInDe, fee, tradeId, tradeType, busiType);
    }

    private void addAcctLog(Acct acct, String feeInDe, BigDecimal fee,
                            String tradeId, String tradeType, String busiType) {

        AcctLog acctLog = new AcctLog();
        acctLog.setAcctId(acct.getAcctId());
        acctLog.setUserId(acct.getUserId());
        acctLog.setAcctType(acct.getAcctType());
        acctLog.setFeeInDe(feeInDe);
        acctLog.setFee(fee);
        acctLog.setBalanceFee(acct.getBalanceFee());
        acctLog.setTradeId(tradeId);
        acctLog.setTradeType(tradeType);
        acctLog.setBusiType(busiType);
        Date now = new Date();
        acctLog.setCreateTime(now);
        acctLog.save();

    }

}
